#include "stdio.h"
#include "stdint.h"
#include "string.h"
#include "global.h"
#include "syscall.h"

#define va_start(ap, v) ap = (va_list)&v        	// 把ap指向第一个固定参数v
#define va_arg(ap, t) *((t*)(ap += 4))	         	// ap指向下一个参数并返回其值
#define va_end(ap) ap = NULL		               	// 清除ap

/* 将整型转换成字符(integer to ascii) */
static void itoa(uint32_t value, char** buf_ptr_addr, uint8_t base) {
   	uint32_t m = value % base;	                  	// 求模,最先掉下来的是最低位   
   	uint32_t i = value / base;	                  	// 取整
   	if (i) {			                            // 如果倍数不为0则递归调用。
      	itoa(i, buf_ptr_addr, base);
   	}
   	if (m < 10) {     								// 如果余数是0~9
      	*((*buf_ptr_addr)++) = m + '0';	  			// 将数字0~9转换为字符'0'~'9'
   	} 
	else {	      									// 否则余数是A~F
      	*((*buf_ptr_addr)++) = m - 10 + 'A'; 		// 将数字A~F转换为字符'A'~'F'
   	}
}

/* 将参数ap按照格式format输出到字符串str,并返回替换后str长度 */
uint32_t vsprintf(char* str, const char* format, va_list ap) {
	char* buf_ptr = str;
	const char* index_ptr = format;
	char index_char = *index_ptr;
	int32_t arg_int;
	char* arg_str;
	while(index_char) {
		if (index_char != '%') {
			*(buf_ptr++) = index_char;
			index_char = *(++index_ptr);
			continue;
		}
		index_char = *(++index_ptr);	 			// 得到%后面的字符
		switch(index_char) {
	 	case 's':
	    	arg_str = va_arg(ap, char*);
	    	strcpy(buf_ptr, arg_str);
	    	buf_ptr += strlen(arg_str);
	    	index_char = *(++index_ptr);
	    	break;
	 	case 'c':
	    	*(buf_ptr++) = va_arg(ap, char);
	    	index_char = *(++index_ptr);
	    	break;
		case 'd':
	    	arg_int = va_arg(ap, int);
	    	if (arg_int < 0) {
	       		arg_int = 0 - arg_int;	/* 若是负数, 将其转为正数后,再正数前面输出个负号'-'. */
	       		*buf_ptr++ = '-';
	    	}
	    	itoa(arg_int, &buf_ptr, 10); 
	    	index_char = *(++index_ptr);
	    	break;
		case 'x':
			arg_int = va_arg(ap, int);
			itoa(arg_int, &buf_ptr, 16); 	
			index_char = *(++index_ptr); 			// 跳过格式字符并更新index_char
			break;
		}
	}
	return strlen(str);
}

/* 格式化输出字符串format */
uint32_t printf(const char* format, ...) {
   va_list args;
   va_start(args, format);	       					// 使args指向format
   char buf[1024] = {0};	       					// 用于存储拼接后的字符串
   vsprintf(buf, format, args);
   va_end(args);
   return write(buf); 
}
